home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
EDIT_UTL
/
OBINED
/
OBINED.PAS
next >
Wrap
Pascal/Delphi Source File
|
1991-03-04
|
33KB
|
948 lines
{
┌────────────────────────────────────────────┐
│ OBINED.PAS │
│ Object oriented for Version 6 Pascal │
│ plus Kim Kokkonen's event handler tweak │
│ see credits after end. │
╞════════════════════════════════════════════╡
│ Vince Risi : Prodigy Computing (PTY) Ltd. │
│ Compuserve [72427,3434] │
│ Johannesburg, South Africa 886-7122 │
└────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────────┐
│You will need BINED.OBJ and EVENT.OBJ from the version 4 editor toolbox│
│in order to compile this to a .tpu. │
└───────────────────────────────────────────────────────────────────────┘
}
{$A-}
{$I-}
{$S-}
{$R-}
unit obined;
{-The binary editor (of Borland) interface for Turbo Pascal version 6}
interface
const
MaxFileSize = $FFE0; {Maximum file size editable by Binary Editor}
EdOptInsert = $1; {Insert on flag}
EdOptIndent = $2; {Autoindent on flag}
EdOptTAB = $8; {Tab on flag}
EdOptBlock = $10; {Show marked block}
EdOptNoUpdate = $20; {Don't update screen when entering editor}
EventKBflag = 1; {Scroll, num or caps locks modified mask}
CAnorm = #255#1; {Activates CRT "normal" attribute}
CAlow = #255#2; {Activates CRT "low" - }
CAblk = #255#3; {Activates CRT "block" - }
CAerr = #255#4; {Activates CRT "error" - }
EdStatTextMod = 1; {Text buffer modified mask}
type
AttrArray = array[0..3] of Byte;
ASCIIZ = array[0..255] of Char;
ASCIIZptr = ^ASCIIZ;
TextBuffer = array[0..$FFF0] of Char;
EdintRecP = ^EdIntRec;
EdIntRec = object
function CurrLineOfs : Word;
{-Return text buffer offset at start of current line}
function CurrChar : Char;
{-Return character at cursor position}
function LinePos : Byte;
{-Return cursor position within current line, 1..247}
function LineLen : Byte;
{-Return length of current line}
function CurrLine : string;
{-Return the current line as a string}
function EditOptions : Byte;
{-Return the current editor options}
procedure ClearKbd;
{-Clears both the BIOS and internal BINED keyboard buffers}
procedure StuffKey(W : Word);
{-Stuffs a keystroke into the keyboard buffer}
private
EditSeg : Word; {Segment where editor control block is located}
BuffOfs : Word; {Offset in EditSeg where text buffer starts}
LineOfs : Word; {Offset in EditSeg where offset of current line is stored}
StrtOfs : Word; {Offset in EditSeg where line buffer is stored}
CurrOfs : Word; {Offset in EditSeg where offset of position in line buffer is stored}
CharOfs : Word; {Offset in EditSeg of character buffer}
OptnOfs : Word; {Offset in EditSeg of editor options}
procedure Find(var EdD);
{-Initialize an internal data record}
end;
CRTinsStruct = record
CRTtype : Byte; {1=IBM, 0=Non}
CRTx1, CRTy1,
CRTx2, CRTy2 : Byte; {Initial window size}
CRTmode : Byte; {Initial mode 0-3,7 or FF(default)}
CRTsnow : Byte; {0 if no snow, don't care for mono}
AttrMono : AttrArray; {CRT attributes for mono mode}
AttrBW : AttrArray; {CRT attributes for b/w modes}
AttrColor : AttrArray; {CRT attributes for color modes}
end;
CIptr = ^CRTinsStruct;
EdInsStruct = record
ComTablen : Word; {Maximum length of command table}
ComTab : TextBuffer; {Command table}
end;
EIptr = ^EdInsStruct;
MIinsStruct = record
Ver : Byte; {Main version}
VerSub : Byte; {Sub version}
VerPatch : Char; {Patch level}
CPUmhz : Byte; {CPU speed for delays}
CIstruct : CIptr; {Points to CRT installation record}
EIstruct : EIptr; {Points to Editor installation area}
DefExt : ASCIIZptr; {Points to ASCIIZ default extension}
end;
MIptr = ^MIinsStruct;
EdCB = object
constructor Init(
DataLen : Word; {Size of binary editor workspace}
Cx1 : Byte; {Editor window, upper left x 1..80}
Cy1 : Byte; {Editor window, upper left y 1..25}
Cx2 : Byte; {Editor window, lower right x 1..80}
Cy2 : Byte; {Editor window, lower right y 1..25}
WaitForRetrace : Boolean; {True for snowy color cards}
Coptions : Word; {Initial editor options}
DefExtension : string; {Default file extension (must start with period)}
var ExitCommands; {Commands to exit editor}
UserEventProcPtr: Pointer {Pointer to user event handler}
);
{-Innitialise an instance of the binary editor}
{Fails if not enough memmory is available }
function Read(Fname : string) : Word;
{-Read a file into the binary editor buffer space,
returning a status code}
{
Status codes -
0 = Successful read
1 = File not found, new file assumed
2 = File too large to edit
}
procedure Reset;
{-Call the editor reset procedure}
function Use(StartCommands : string) : Integer;
{-Edit file, using startcommands, and returning an exitcode}
{
Exit codes -
-1 = Editing terminated with ^KD
0 = Editing terminated with first user-specified exit command
1 ...
}
function Modified : Boolean;
{-Return true if text buffer was modified during edit}
function FileName : string;
{-Return the current file pathname of the specified control block}
procedure ChangeName(fname : string);
{-rename pathname of the specified control block}
function Save(MakeBackup : Boolean) : Word;
{-Save the current file in the editor text buffer,
returning a status code}
{
Status codes -
0 = Successful save
1 = File creation error
2 = Disk write error
3 = Error closing file
}
destructor Done;
private
x1, y1, x2, y2 : Byte; {Upper left and lower right corners of editor window}
DataSeg : Word; {Segment address of editor data area}
DataSegLen : Word; {Requested data area length (bytes)}
Options : Word; {Bit flags for editor options}
FileStr : ASCIIZptr; {Points to ASCIIZ filename}
Commands : ASCIIZptr; {Points to ASCIIZ string of editor commands}
Reserved1 : ASCIIZptr; {Not used here}
Reserved2 : ASCIIZptr; {Not used here}
Event : Pointer; {Points to event handling procedure}
Buffer : ^TextBuffer;{Points to text area}
BufSize : Word; {Available size for text}
MIstruct : MIptr; {Points to main installation record}
ComTab : ASCIIZptr; {Points to terminate command table}
EOtext : Word; {Current number of chars in text buffer}
CursorPos : Word; {Current cursor position in buffer}
BlockStart : Word; {Start of marked block in buffer}
BlockEnd : Word; {End of marked block in buffer}
Status : Word; {Editor status}
DataPtr : ^TextBuffer;{Points to Turbo heap block allocated for text buffer}
Internals : edintrec; {points to internals}
end;
const
{CRT attributes for normal low blk error}
MonoArray : AttrArray = ($7, $70, $F, $F0);
BwArray : AttrArray = ($7, $70, $F, $F0);
ColorArray : AttrArray = ($1F, $38, $71, $4F);
var
CurrInternals : edintrecP;
procedure CRTputFast(x, y : Word; s : string);
{-Use binary editor services to write a string to the screen}
{x in 1..25, y in 1..80}
function ExpandPath(Fname : string) : string;
{-Return a complete path using the binary editor services}
implementation
{$L BINED}
procedure pAssign(var fromstr, tostr : ASCIIZ); external;
procedure cCrtPutf(var s : ASCIIZ; r, c : Word); external;
procedure EditInit(var EdData); external;
procedure EditNew(var EdData); external;
function Editor(var EdData) : Integer; external;
var
UserEventAddr : Pointer;
{$L EVENT}
procedure EventCheck(pinfo, peventno : Word); far; external;
function AsciizToStr(a : ASCIIZ) : string;
var
s : string;
slen : Byte absolute s;
begin
slen := 0;
while a[slen] <> #0 do
slen := Succ(slen);
Move(a, s[1], slen);
AsciizToStr := s;
end;
procedure StrToAsciiz(s : string; var a : ASCIIZ);
var
slen : Byte absolute s;
begin {StrToAsciiz}
Move(s[1], a, slen);
a[slen] := #0;
end; {StrToAsciiz}
procedure CRTputFast(x, y : Word; s : String);
var
a : ASCIIZ;
begin {CRTputFast}
{Create ASCIIZ string}
StrToAsciiz(s, a);
cCrtPutf(a, Pred(y), Pred(x));
end; {CRTputFast}
function ExpandPath(Fname : String) : String;
var
fromstr, tostr : ASCIIZ;
function StupCase(s : string) : string;
var
i : Word;
begin {StupCase}
for i := 1 to Length(s) do
s[i] := UpCase(s[i]);
StupCase := s;
end; {StupCase}
begin {ExpandPath}
{Create ASCIIZ string from input}
StrToAsciiz(Fname, fromstr);
{Call the binary editor service}
pAssign(fromstr, tostr);
{Get Turbo string from Asciiz}
ExpandPath := StupCase(AsciizToStr(tostr));
end; {ExpandPath}
constructor EdCB.Init(DataLen : Word; Cx1, Cy1, Cx2, Cy2 : Byte;
WaitForRetrace : Boolean; Coptions : Word;
DefExtension : String; var ExitCommands;
UserEventProcPtr : Pointer);
{-Initialize the binary editor, returning a status code}
var
nofs, bofs, codelen : Word;
begin
{Initialize the editor control block}
DataSegLen := DataLen;
if MaxAvail < DataSegLen then begin
{Insufficient data space}
fail;
end;
GetMem(DataPtr, DataSegLen+15);
{Assure data space paragraph aligned}
if Ofs(DataPtr^) <> 0 then
DataSeg := Succ(Seg(DataPtr^))
else
DataSeg := Seg(DataPtr^);
x1 := Pred(Cx1);
x2 := Pred(Cx2);
y1 := Pred(Cy1);
y2 := Pred(Cy2);
Options := Coptions;
GetMem(FileStr, 72); {Space for max length file string}
GetMem(Commands, 256); {Room for 255 bytes of startup keystrokes}
FillChar(Commands^, 256, #0); {No startup commands right now}
GetMem(Reserved1, 8); {Null out unused fields}
FillChar(Reserved1^, 8, #0);
Reserved2 := nil;
if UserEventProcPtr = nil then
{Disable event checking}
Event := nil
else begin
{Set up for user event checking}
Event := Addr(EventCheck);
UserEventAddr := UserEventProcPtr;
end;
Buffer := nil; {Returned by Binary editor after initialization}
BufSize := 0; {Returned by Binary editor after initialization}
{Allocate and initialize main installation area}
New(MIstruct);
with MIstruct^ do begin
Ver := 4;
VerSub := 0;
VerPatch := 'A'; {4.0A}
CPUmhz := 5; {CPU speed in MHz - not critical}
New(CIstruct);
with CIstruct^ do begin
CRTtype := 1;
CRTx1 := 0;
CRTy1 := 0;
CRTx2 := 79;
CRTy2 := 24; {Change to 42 for EGA 43 line mode}
CRTmode := $FF; {Default screen mode}
if WaitForRetrace then
CRTsnow := $FF
else
CRTsnow := $0;
AttrMono := MonoArray;
AttrBW := BwArray;
AttrColor := ColorArray;
end;
EIstruct := nil; {Command installation record set by Binary Editor}
GetMem(DefExt, 8); {Default file extension}
StrToAsciiz(DefExtension, DefExt^);
end;
{Install special exitcommands}
ComTab := Addr(ExitCommands);
{Position and status variables used by editor}
EOtext := 0;
CursorPos := 0;
BlockStart := 0;
BlockEnd := 0;
Status := 0;
{Call the binary editor initialization procedure}
EditInit(x1);
internals.Find(self);
end; {InitBinaryEditor}
function EdCB.Read(Fname : String) : Word;
const
ctrlz = #26;
var
f : file;
fsize : longint;
zpos, bytesread : Word;
begin
Fname := ExpandPath(Fname);
StrToAsciiz(Fname, FileStr^);
{See whether file exists}
Assign(f, Fname);
system.Reset(f, 1);
if IOResult <> 0 then begin
{Couldn't open file, assume a new one}
EOtext := 0;
Buffer^[EOtext] := #0;
Read := 1;
Exit;
end;
{Check the file size}
fsize := FileSize(f);
if fsize > BufSize then begin
{File too big}
Read := 2;
Close(f);
Exit;
end;
{Read the file}
BlockRead(f, Buffer^, fsize, bytesread);
Close(f);
EOtext := fsize;
{Scan for control Z in last sector of file}
if EOtext < 512 then
zpos := 0
else
zpos := EOtext-512;
while zpos <> EOtext do
if Buffer^[zpos] = ctrlz then
EOtext := zpos
else
inc(zpos);
Buffer^[EOtext] := #0;
{Exit with success code}
Read := 0;
end;
procedure EdCB.Reset;
var junk : word; {!!}
begin
EditNew(x1);
end;
function EdCB.Use(StartCommands : String) : Integer;
begin {UseBinaryEditor}
CurrInternals := @Internals;
{Put the start commands into the editor control block}
if Length(StartCommands) > 0 then
Move(StartCommands[1], Commands^, Length(StartCommands));
{Call the editor}
Use := Editor(x1);
end; {UseBinaryEditor}
function EdCB.Modified : Boolean;
{-Return true if text buffer was modified during edit}
begin {ModifiedFileBinaryEditor}
Modified := (Status and EdStatTextMod) <> 0;
end; {ModifiedFileBinaryEditor}
function EdCB.FileName: String;
{-Return the file name in the specified control block}
begin {FileNameBinaryEditor}
FileName := AsciizToStr(FileStr^);
end; {FileNameBinaryEditor}
procedure EdCB.ChangeName(fname : string);
begin {FileNameBinaryEditor}
{Expand the pathname and store it in editor control block}
Fname := ExpandPath(Fname);
StrToAsciiz(Fname, FileStr^);
end;
function EdCB.Save(MakeBackup : Boolean) : Word;
{-Save the current file in the editor text buffer, returning a status code}
var
f : file;
Fname : string;
i, byteswritten : Word;
function Exist(Fname : string; var f : file) : Boolean;
{-Return true and assigned file handle if file exists}
var
i : Word;
begin {Exist}
Assign(f, Fname);
System.Reset(f);
Exist := (IOResult = 0);
Close(f);
{Clear ioresult}
i := IOResult;
end; {Exist}
procedure MakeBakFile(NewName : string);
{-Make a backup file}
var
nf, bf : file;
BakName : string;
DotPos : Byte;
C : Char;
begin {MakeBakFile}
if Exist(NewName, nf) then begin
{Workfile already exists, back it up}
{Find position of last period in NewName}
DotPos := Succ(Length(NewName));
repeat
dec(DotPos);
C := NewName[DotPos];
until (C = '.') or (C = '\') or (C = ':') or (DotPos = 0);
if (dotpos = 0) or (C <> '.') then
bakname := newname+'.BAK'
else
bakname := Copy(NewName, 1, dotpos)+'BAK';
if Exist(bakname, bf) then
{Backup already exists, erase it}
Erase(bf);
{Rename existing file to backup}
Rename(nf, bakname);
end;
end; {MakeBakFile}
begin {SaveFileBinaryEditor}
Fname := AsciizToStr(FileStr^);
if MakeBackup then
MakeBakFile(Fname);
Assign(f, Fname);
Rewrite(f, 1);
if IOResult <> 0 then begin
Save := 1;
Close(f);
i := IOResult; {Clear ioresult}
Exit;
end;
BlockWrite(f, Buffer^, Succ(EOtext), byteswritten);
if (byteswritten <> Succ(EOtext)) or (IOResult <> 0) then begin
Save := 2;
Close(f);
Exit;
end;
Close(f);
if IOResult <> 0 then begin
Save := 3;
Exit;
end;
{Reset editor modified bit}
Status := 0;
{Success status}
Save := 0;
end;
destructor edcb.done;
{-Release heap space used by a binary editor control block}
begin {ReleaseBinaryEditorHeap}
FreeMem(DataPtr, DataSegLen+15);
FreeMem(FileStr, 72);
FreeMem(Commands, 256);
FreeMem(Reserved1, 8);
Dispose(MIstruct^.CIstruct);
FreeMem(MIstruct^.DefExt, 8);
Dispose(MIstruct);
end;
const
KbdStart = $1E;
KbdEnd = $3C;
type
Barray = array[0..30000] of Byte;
BarrayPtr = ^Barray;
SO =
record
O : Word;
S : Word;
end;
var
KbdHead : Word absolute $40 : $1A;
KbdTail : Word absolute $40 : $1C;
function Search(var Buffer; BuffLen : Word;
var Match; MatchLen : Word) : Pointer;
{-Return pointer to start of match, nil if none}
var
B : BarrayPtr;
M : BarrayPtr;
I : Word;
J : Word;
Matched : Boolean;
begin
B := @Buffer;
M := @Match;
for I := 1 to BuffLen do begin
if B^[0] = M^[0] then begin
{Start of a match, try the rest}
if MatchLen = 1 then
Matched := True
else begin
J := 1;
repeat
Matched := (B^[J] = M^[J]);
Inc(J);
until not Matched or (J = MatchLen);
end;
if Matched then begin
{Complete match}
Search := B;
Exit;
end;
end;
{Move to next byte}
Inc(SO(B).O);
end;
{No match}
Search := nil;
end;
function CodeMatch(B, M : BarrayPtr; Len : Word) : Boolean;
{-Return true if B^ matches M^ after discounting addresses}
var
MB : Byte;
I : Word;
begin
for I := 0 to Len-1 do begin
MB := M^[I];
if MB <> 0 then
if MB <> B^[I] then begin
CodeMatch := False;
Exit;
end;
end;
CodeMatch := True;
end;
procedure EdintRec.Find(var EdD);
{-Initialize an internal data record}
type
WordPtr = ^Word;
const
{Code we must find to determine data offsets}
Match0 : array[0..7] of Byte =
($C3, {RET}
$C3, {RET}
$F6, $06, $00, $00, $01, {TEST [Options],01}
$C3); {RET}
Match1 : array[0..18] of Byte =
($C6, $07, $1A, {MOV BYTE PTR [BX],1Ah}
$8B, $16, $00, $00, {MOV DX,[LineOfs]}
$2B, $16, $00, $00, {SUB DX,[BuffOfs]}
$BE, $00, $00, {MOV SI,StrtOfs}
$FC, {CLD}
$3B, $36, $00, $00); {CMP SI,[CurrOfs]}
Match2 : array[0..7] of Byte =
($5B, {POP BX}
$80, $3E, $00, $00, $FF, {CMP [BufChar],$FF}
$B0, $FF); {MOV AL,$FF}
var
EdData : Edcb absolute EdD;
B0 : BarrayPtr;
B1 : BarrayPtr;
B2 : BarrayPtr;
begin
{All zeros will indicate error}
FillChar(self, SizeOf(self), 0);
{B0 is base of the binary editor code segment}
B0 := Ptr(Seg(EditInit), 0);
{Find code for editor options}
B0 := Search(B0^, 10000, Match0, 4);
if B0 = nil then
{Not found}
Exit;
if not CodeMatch(B0, @Match0, SizeOf(Match0)) then
{Not a complete match}
Exit;
{Find code for various buffer offsets}
B1 := Search(B0^, 10000, Match1, 5);
if B1 = nil then
Exit;
if not CodeMatch(B1, @Match1, SizeOf(Match1)) then
Exit;
{Find code for character buffer}
B2 := Search(B1^, 10000, Match2, 3);
if B2 = nil then
Exit;
if not CodeMatch(B2, @Match2, SizeOf(Match2)) then
Exit;
{Initialize the internals record}
EditSeg := EdData.DataSeg;
BuffOfs := SO(EdData.Buffer).O;
OptnOfs := WordPtr(@B0^[4])^;
LineOfs := WordPtr(@B1^[5])^;
StrtOfs := WordPtr(@B1^[12])^;
CurrOfs := WordPtr(@B1^[17])^;
CharOfs := WordPtr(@B2^[3])^;
end;
function Edintrec.CurrLineOfs : Word;
{-Return text buffer offset of start of current line}
begin
if EditSeg = 0 then
CurrLineOfs := $FFFF
else
CurrLineOfs := MemW[EditSeg:LineOfs]-BuffOfs;
end;
function Edintrec.CurrChar : Char;
{-Return character at cursor position}
begin
if EditSeg = 0 then
CurrChar := #$FF
else
CurrChar := Char(Mem[EditSeg:MemW[EditSeg:CurrOfs]]);
end;
function Edintrec.LinePos : Byte;
{-Return cursor position within current line}
begin
if EditSeg = 0 then
LinePos := $FF
else
LinePos := MemW[EditSeg:CurrOfs]-StrtOfs+1;
end;
function Edintrec.LineLen : Byte;
{-Return length of current line}
var
O : Word;
begin
if EditSeg = 0 then
LineLen := $FF
else begin
O := StrtOfs+247;
while (O >= StrtOfs) and (Mem[EditSeg:O] = $20) do
Dec(O);
LineLen := O+1-StrtOfs;
end;
end;
function Edintrec.CurrLine : string;
{-Return the current line as a string}
var
L : string;
LL : Byte absolute L;
begin
LL := LineLen;
if LL = $FF then
LL := 0
else
Move(Mem[EditSeg:StrtOfs], L[1], LL);
CurrLine := L;
end;
function Edintrec.EditOptions : Byte;
{-Return the current editor options}
begin
if EditSeg = 0 then
EditOptions := $FF
else
EditOptions := Mem[EditSeg:OptnOfs];
end;
procedure Edintrec.ClearKbd;
{-Clears both the BIOS and internal BINED keyboard buffers}
begin
if EditSeg <> 0 then begin
{Clear BIOS keyboard buffer}
KbdHead := KbdTail;
{Clear BINED character buffer}
Mem[EditSeg:CharOfs] := $FF;
end;
end;
procedure Edintrec.StuffKey(W : Word);
{-Stuffs a keystroke into the keyboard buffer}
var
SaveKbdTail : Word;
begin
SaveKbdTail := KbdTail;
if KbdTail = KbdEnd then
KbdTail := KbdStart
else
Inc(KbdTail, 2);
if KbdTail = KbdHead then
{Buffer full, ignore request}
KbdTail := SaveKbdTail
else
MemW[$40:SaveKbdTail] := W;
end;
end.
________________________________________________________________________________
{ BINED.PAS
BINED 4.0
Copyright (c) 1985, 87 by Borland International, Inc. }
{
BININT offers a way to access normally hidden information while within a
BINED event handler. See BININT.DOC for details. (follows)
Written by Kim Kokkonen, TurboPower Software.
Released to the public domain.
Compuserve [72457,2131]
Version 1.0, 10/22/88
first release
}
BININT
Accessing BINED Internal Information in Event Handlers
Version 1.0
Kim Kokkonen
Overview
------------------------------------------------------------------------------
BININT is a small unit that may be used in programs based on the binary
editor, BINED, from Borland's Editor Toolbox. It removes a drawback of BINED,
which is that accurate information about the cursor position (within the
current line and text buffer) is not available to event handlers. As such,
event handlers are limited in what they can do.
When accurate information is available to a BINED event handler, new
horizons open up for using the binary editor. We developed this unit in
order to add limited mouse support to BINED, which required knowing the
cursor position relative to the overall file size. Another popular request
is to add word-wrap to BINED -- knowing the information provided by BININT, an
event handler could be written to add word wrap.
BININT is a dirty little unit, peeking into the BINED code segment to read
certain offsets of data items that it needs to compute accurate information
for use by an event handler. Even so, BININT is very careful to assure that
the information it uses is correct. If BININT can't find the appropriate
offsets, it will fail gracefully, but in this case an event handler won't
have the information it needs. So far this isn't much of a concern since to
our knowledge Borland has released only a single version of BINED. BININT is
designed to adjust itself automatically whenever possible, even if BINED is
changed in the future.
In the following, we assume you know what is meant by a BINED "event handler".
See Borland's documentation, or the supplied example TEST.PAS, for background.
Using BININT
------------------------------------------------------------------------------
Just add BININT to your USES list, after BINED itself. (BININT depends on
BINED.) Then your application can call any of the following procedures and
functions.
procedure FindInternals(EdData : EdCB; var E : EdIntRec);
Call FindInternals any time after calling Borland's InitBinaryEditor
routine, but before calling UseBinaryEditor. This routine initializes the
record parameter E to hold information needed to track the specified edit
window EdData. The program must declare a global variable of type EdIntRec
to store the binary editor internals information for use by the event
handler. Note that you will need a separate EdIntRec variable for each
BINED edit window.
If for some reason BININT cannot find the appropriate locations in BINED, it
will return all fields of the EdIntRec set to zero. This may be considered
a critical error for any program using BININT even though the rest of
BININT's functions are designed to return safe values in this case. You can
test for correct operation of FindInternals with the following statement:
if E.EditSeg = 0 then
{Critical error, unknown BINED version} ;
The remaining BININT functions are intended for use within an event handler.
Each of them requires a parameter of type EdIntRec, previously initialized by
a call to FindInternals.
function CurrLineOfs(var E : EdIntRec) : Word;
This routine returns the byte offset within BinEd's text buffer of the first
character on the current line. For example, if the cursor is on the first
line of a text file, CurrLineOfs will return 0. If the first line has 10
characters (counting CR and LF), then CurrLineOfs will return 10 when the
cursor is on the second line of the file. When the cursor is moved to the
end of the file, CurrLineOfs returns the same value as EdData.EOtext. If the
EdIntRec was not correctly initialized, CurrLineOfs returns $FFFF.
Note that CurrLineOfs does not vary when the cursor is moved within a given
line. The LinePos function provides that information.
function CurrChar(var E : EdIntRec) : Char;
CurrChar returns the ASCII character associated with the current cursor
position in the file. If the cursor is beyond the end of the current line,
CurrChar returns a blank (#32). CurrChar will not return a CR (#13), LF
(#10), or EOF (#26) unless the text file is corrupt. If the EdIntRec was not
correctly initialized, CurrChar returns #255.
function LinePos(var E : EdIntRec) : Byte;
LinePos returns the position of the cursor in the current line. It returns 1
for the first character in the line. The highest value normally returned
will be 249. If the EdIntRec was not correctly initialized, LinePos returns
255.
Note that you can't add LinePos to CurrLineOfs and obtain an offset that
means anything. BINED copies the current line to a separate buffer for
editing and recopies it to the main text buffer only when the cursor leaves
the line. Hence, the contents of the text buffer beyond CurrLineOfs are not
guaranteed to be up to date. Use the CurrLine function to get the contents
of the current text line.
function LineLen(var E : EdIntRec) : Byte;
Returns the length of the current line. The length is defined as the number
of characters up to and including the last non-blank character in the line.
Note that the cursor is allowed to move beyond this position, and thus you
will have situations where LinePos > LineLen. If the EdIntRec was not
correctly initialized, LineLen returns 255.
function CurrLine(var E : EdIntRec) : string;
Returns the current text line as a string. There's no need to call LineLen
if you call CurrLine since the length of the returned string equals LineLen.
If the EdIntRec was not correctly initialized, CurrLine returns an empty
string.
function EditOptions(var E : EdIntRec) : Byte;
Returns the current value of the editor options (which may have been changed
by the user since the edit session started). See the constants near the top
of BINED.PAS (EdOptInsert and so on) for masks to decode this bit-mapped
byte.
Note that BININT is not designed to let you _modify_ any of the data that it
provides. Within an event handler, it is not safe to change the cursor
position, or directly modify the line buffer.
If modification of the text stream is desired (as would be the case when
adding word wrap to BINED), the appropriate action is to poke characters into
the keyboard buffer. For this reason, BININT provides two more procedures:
procedure ClearKbd(var E : EdIntRec);
Before poking a character, it is best to call this routine. ClearKbd clears
not only the BIOS keyboard buffer, but also an internal single byte buffer
used by BINED to hold extended keystrokes.
procedure StuffKey(W : Word);
This stuffs one character (ASCII value with scan code) into the keyboard
buffer. If the character is not extended (like <F1> or <Left>) it is alright
to call StuffKey as follows:
StuffKey(Ord(CharToStuff));
For example
StuffKey(Ord(^M));
puts a carriage return into the keyboard buffer, to be acted upon by BINED
when the event handler returns.
For an extended character, pass the appropriate word value. For example
StuffKey($4B00);
stuffs a <Left> arrow into the keyboard buffer.
Remember that the keyboard buffer normally holds only 16 characters. If the
buffer is full when StuffKey is called, it does nothing.
Examples
------------------------------------------------------------------------------
The supplied program TEST1.PAS is a tiny example of using BININT. It allows
you to browse through a file while continuously showing a status report of the
information offered by BININT. Just compile TEST1.PAS and run it by specifying
a text file to browse on the command line:
TEST1 FileToBrowse
Press ^KD to quit. No changes will be saved.
TEST2 is a frivolous example of modifying the text stream by stuffing
characters into the keyboard buffer. Compile and run it just like TEST1. In
TEST2, whenever the cursor is positioned over a space within a text line, the
event handler breaks the text onto the next line, leading to a
semi-interactive "one word per line" filter. If the editor is in overwrite
mode, the event handler does nothing. Like TEST1, TEST2 does not allow you to
save the resulting file.
Disclaimer
------------------------------------------------------------------------------
The BININT unit was written by Kim Kokkonen of TurboPower Software. It is
hereby released to the public domain. We accept no liability for the use of
this software, and make no guarantees as to its performance. Good luck! We'd
like to hear from the first person to develop a word-wrapping event handler
for BINED.